昨天看到一个面试题:怎样实现 isNaN()
方法?
细细研究了一下 NaN,发现这个东西不常用,坑却异常多,颇有 “茴” 字有几种写法的感觉,这里记录下总结的东西吧。
NaN
是什么
NaN
即 Not a Number(非数值),但它是一个特殊的数值,所以:
typeof(NaN) // "number"
编码时很少直接使用 NaN
,通常是在计算失败时,作为 Math
的某个方法的返回值出现的。
它有两个重要的性质:
-
NaN
与任何值都不相等,包括NaN
自身:
alert(NaN == NaN) // false
alert(NaN === NaN) // false
- 任何涉及
NaN
的操作都会返回NaN
。
哪些情况会产生NaN
?
1. 计算
JS 在进行加减乘除运算之前,会先调用 Number()
方法,将非数值的运算项转化为数值,如果转换失败就返回NaN
,比如:
1-'a'; // NaN
首先是执行Number('a')
,不能成功转化为数值,返回NaN
,再利用NaN
的第二条性质:任何涉及 NaN
的操作都会返回NaN
,所以最终的结果是NaN
。
2. 类型转换
当一个值不能被Number
,parseInt
,parseFloat
成功转换为数值,就返回NaN
,举例:
Number('123.456abc'); // NaN
parseInt('123.456abc'); // 123
parseFloat('123.456abc'); // 123.456
Number('abc'); // NaN
parseInt('abc'); // NaN
parseFloat('abc'); // NaN
Number([]); // 0
parseInt([]); // NaN
parseFloat([]); // NaN
Number(''); // 0
parseInt(''); // NaN
parseFloat(''); // NaN
Number({}); // NaN
parseInt({}); // NaN
parseFloat({}); // NaN
这里要注意三者之间的差异,我的理解是 parseInt
,parseFloat
会尽量将参数值转化为数值。
关于isNaN()
isNaN
是window
对象的一个方法,比较诡异的是:isNaN(x)
并不是判断参数x
本身是不是NaN
,而是判断Number(x)
是不是NaN
。也就是说先用Number()
去转化参数,再去判断转化的结果。返回的结果是一个布尔值。
isNaN(NaN); // true
isNaN(123); // false
isNaN('abc'); //true
isNaN('123abc'); //true
isNaN({}); // true,因为Number({})=NaN
isNaN(''); // false, 因为Number('')=0
isNaN([]); // false,因为Number([])=0
可以看到最后, 空字符串''
和 空数组[]
显然是非数值,而isNaN
返回了false
,原因就是Number
转换在作怪,这点还是很诡异的...所以我选择慎用...
那么isNaN
是怎么实现的呢,原理就是利用NaN
的第一条性质:NaN
与任何值都不相等,包括NaN
自身。
var isNaNA = function(value) {
var n = Number(value);
return n !== n;
};
先用Number()
转换参数,再判断转换后的结果是不是不等于自身。
而 MDN 上给的实现方式是这样的:
var isNaNB = function(value) {
var n = parseInt(value);
return n !== n;
};
我觉得是有问题的,因为:
isNaN('123abc'); // true
isNaNA('123abc'); // true
isNaNB('123abc'); // false
Number.isNaN()
ES6 中的Number.isNaN()
是一个判断NaN
的升级版,和isNaN()
不同的是,Number.isNaN()
不会强制转化参数,直接对参数本身做判断,这样只有参数显示等于NaN
,才会返回true
Number.isNaN(NaN); // true,其他情况都返回 false
它的实现原理是:
function isNaNC (value) {
return typeof(value) === "number" && isNaN(value);
}
算了,还是不纠结了....
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。